package com.kt.thread.demo;

/**
 * Created by tangwy on 2016/1/11.
 * Java线程互斥测试,想要让线程执行出现互斥，只需要让线程锁锁住的是同一个对象即可，如有Thread1,Thread2,Thread3三个线程
 * 只要让三个线程锁住同一个对象，就能实现线程之间的互斥
 */
public class SynchronizedTest {
    /**
     * 如果有有多个线程运行output1方法，有可能出现第一个线程的s还没有完整输出，如ABC有可能只输出AB
     * 第二个线程就已经进来执行，为了让s完整的输出，则必须加上线程锁。
     * @param s
     */
    public void output1(String s){
        for(int i=0;i<s.length();i++){
            System.out.print(s.charAt(i));
        }
        System.out.println();
    }


    /**
     * 只要是同一个对象调用output2，因为用于同步的锁是this，
     * 如 com.kt.thread.demo.SynchronizedTest obj1=new com.kt.thread.demo.SynchronizedTest();
     *    com.kt.thread.demo.SynchronizedTest obj2=obj1;
     *    obj1.output2();
     *    obj2.output2();
     * 这个代码便能实现互斥，因为obj1和obj2是同一个对象,this指向的是同一个对象
     *
     * @param s
     */
    public void output2(String s){
        synchronized (this){
            for(int i=0;i<s.length();i++){
                System.out.print(s.charAt(i));
            }
            System.out.println();
        }
    }

    /**
     * 这个其实和上面的同步代码块是一样的，也是锁住了this对象，
     * 也就是只要同一个对象output3和output2可以实现互斥
     * @param s
     */
    public synchronized void output3(String s){
        for(int i=0;i<s.length();i++){
            System.out.print(s.charAt(i));
        }
        System.out.println();
    }

    /**
     * 如何让output4和output5出现互斥？因为output5是一个静态方法，是没有this的,使用的是类的字节码。
     * 记住同步锁的关键便是锁住是否是同一个对象。因为每个对象所使用的字节码都是同一份
     * 所以可以锁住这个类的字节码即可实现同步，同理如果需要将output2、3、4、5一起互斥
     * 都只需要将同步锁对象改为这个类的字节码即可
     * @param s
     */
    public  synchronized void output4(String s){
        synchronized (SynchronizedTest.class){
            for(int i=0;i<s.length();i++){
                System.out.print(s.charAt(i));
            }
            System.out.println();
        }
    }
    public static synchronized void output5(String s){
        for(int i=0;i<s.length();i++){
            System.out.print(s.charAt(i));
        }
        System.out.println();
    }
}
